package com.hy.ratelimit;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created With IntelliJ IDEA.
 * Descriptions:限流算法之固定窗口
 * <p>
 * User:Mr.Du
 * Date:2024/4/25
 * Time:10:31
 */
public class FixedWindowRateLimiter {
    private final Lock lock = new ReentrantLock();
    private final AtomicInteger counter = new AtomicInteger(0);
    private volatile long lastRequestTime = System.nanoTime();
    private long windowUnit = 1000L;
    private int threshold = 1;

    public FixedWindowRateLimiter(){}

    // 假设存在一个构造函数，用于初始化windowUnit和threshold
    // 这个可以根据业务需求动态配置
    // 默认窗口单位为1000毫秒，阈值为4
    public FixedWindowRateLimiter(long windowUnit, int threshold) {
        this.windowUnit = windowUnit;
        this.threshold = threshold;
    }

    /**
     * 固定窗口时间算法
     * 关注公众号：捡田螺的小男孩
     * @return 是否获取成功
     */
    public boolean fixedWindowsTryAcquire() {
        lock.lock(); // 获取锁
        try {
            long currentTime = System.nanoTime(); // 使用System.nanoTime()提高时间精度
            if (currentTime - lastRequestTime > windowUnit) {
                counter.set(0); // 计数器清0
                lastRequestTime = currentTime; // 开启新的时间窗口
            }
            if (counter.get() < threshold) {
                counter.incrementAndGet(); // 计数统计器加1
                return true;
            }
        } finally {
            lock.unlock(); // 释放锁
        }
        return false;
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);
        FixedWindowRateLimiter fixedWindowRateLimiter = new FixedWindowRateLimiter();
        for (int i = 0; i < 5; i++) {
            executorService.execute(() -> {
//                while (true) {
                    if (fixedWindowRateLimiter.fixedWindowsTryAcquire()) {
                        successCount.incrementAndGet();
                        System.out.println("请求成功，总成功次数：" + successCount.get());
                    } else {
                        failureCount.incrementAndGet();
                        System.out.println("请求失败，总失败次数：" + failureCount.get());
                    }
                    try {
                        Thread.sleep(1); // 模拟请求间隔时间
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
//                }
            });
        }
    }
}
